/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.tencent.tendon.convert.json;

import java.lang.reflect.*;

/**
 *
 * @author nbzhang
 */
public class JsonArrayEncoder<T> extends JsonEncoder<T[]> {

    private final boolean finaled;

    private final Type componentType;

    private final JsonEncodable<T> encoder;

    JsonArrayEncoder(final Type type) {
        super(type);
        if (type instanceof ParameterizedType) {
            final ParameterizedType pts = (ParameterizedType) type;
            this.componentType = pts.getActualTypeArguments()[0];
        } else if (type instanceof Class) {
            Class clazz = (Class) type;
            this.componentType = clazz.getComponentType();
        } else if (type instanceof GenericArrayType) {
            this.componentType = ((GenericArrayType) type).getGenericComponentType();
        } else {
            this.componentType = null;
        }
        this.encoder = this.componentType == null ? JsonAnyEncoder.getInstance() : JsonLoader.loadEncodable(this.componentType);

        this.simpled = encoder != null && encoder.isSimpled();
        this.finaled = (this.componentType instanceof Class) && Modifier.isFinal(((Class) componentType).getModifiers());
    }

    public JsonArrayEncoder(final Class<T[]> type, final Class<T> componentType, final JsonEncodable<T> encoder) {
        super(type);
        this.encoder = encoder;
        this.componentType = componentType;
        this.simpled = encoder != null && encoder.isSimpled();
        this.finaled = java.lang.reflect.Modifier.isFinal(componentType.getModifiers());
    }

    @Override
    public void convertTo(JsonWriter out, T[] value) {
        if (value == null) {
            out.writeNull();
            return;
        }
        if (value.length == 0) {
            out.write('[', ']');
            return;
        }
        if (!simpled) out.offer(value);
        out.write('[');
        boolean first = true;
        if (simpled && finaled) {
            for (T v : value) {
                if (!first) out.write(',');
                encoder.convertTo(out, v);
                if (first) first = false;
            }
        } else {
            final JsonEncodable encoder0 = this.encoder;
            final Type component = this.componentType;
            final T[] values = value;
            if (encoder0 == null) {
                for (Object v : values) {
                    if (!first) out.write(',');
                    JsonAnyEncoder.getInstance().convertTo(out, v);
                    if (first) first = false;
                }
            } else {
                for (Object v : values) {
                    if (!first) out.write(',');
                    if (v == null) {
                        out.writeNull();
                    } else if (v.getClass() == component) {
                        encoder0.convertTo(out, v);
                    } else {
                        JsonAnyEncoder.getInstance().convertTo(out, v);
                    }
                    if (first) first = false;
                }
            }
        }
        out.write(']');
        if (!simpled) out.poll();
    }
}
